package com.creditease.shield.flow.service.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.creditease.shield.flow.cache.CacheContainer;
import com.creditease.shield.flow.dao.KeyBankDao;
import com.creditease.shield.flow.pojo.KeyBankPO;
import com.creditease.shield.flow.service.KeyBankService;
import com.creditease.shield.flow.util.DateUtil;

@Service("keyBankService")
public class KeyBankServiceImpl implements KeyBankService {

//	private static final Logger log = LoggerFactory.getLogger(KeyBankServiceImpl.class);
	
	private static final Map cacheKeyBank = new HashMap();

	@Autowired
	private KeyBankDao baseKeysRepository; 
	
	public String createKey(String name) {
		return getKeyBank(name).createKey();
	}

	public String createKey(String name, String prefix, String subfix, int length) {
		return getKeyBank(name).createKey(prefix, subfix, length);
	}

	public long createKeyAsLong(String name) {
		return getKeyBank(name).createKeyAsLong();
	}

	/**
	 * 从缓存取得KeyBank。如果没有则初始化并添加到缓存。
	 * 
	 * @param name
	 * @return
	 */
	protected KeyBank getKeyBank(String name) {
		
//		if(null == name || name.length()==0 ) throw new Exception("illegal param");
		
		Object result = cacheKeyBank.get(name);
		if (result == null) {
			synchronized (cacheKeyBank) {
				result = cacheKeyBank.get(name);
				if (result == null) {
					// fill bank cache
					KeyBank keyBank = new KeyBank(baseKeysRepository, name);
					if (keyBank.initKeyBank()) {
						result = keyBank;
						cacheKeyBank.put(name, result);
					}
				}
			}
		}
//		if (result == null) {
//			throw new Exception("result is null");
//		}
		return (KeyBank) result;
	}
	
	
	
	protected static class KeyBank {
		private String name = null;
		private KeyBankPO basKeysVO = null;
		private KeyBankDao baseKeysRepository = null;
		// 每一次为keyCurrent到keyMax
		private long keyCurrent = 0;
		private long keyMax = 0;

		public KeyBank(KeyBankDao baseKeysRepository, String name) {
			super();
			this.baseKeysRepository = baseKeysRepository;
			this.name = name;
		}

		public String createKey() {
			return createKey(basKeysVO.getKeyPrefix(), basKeysVO.getKeySubfix(), basKeysVO.getKeyLength()
				.intValue());
		}

		public String createKey(String prefix, String suffix, int length) {
			String strKey = String.valueOf(createKeyAsLong());
			
			prefix = prefix == null ? "" : prefix.trim();
			suffix = suffix == null ? "" : suffix.trim();

			
			prefix = parseValue(prefix);
			
			suffix = parseValue(suffix);
				
			
			int maxLen = length - prefix.length() - suffix.length();
			if (strKey.length() > maxLen) {
				strKey = strKey.substring(strKey.length() - maxLen);
			}
			
			int zeroLen = length - prefix.length() - strKey.length() - suffix.length();
			StringBuffer sb = new StringBuffer(length);
			sb.append(prefix);
			for (int i = 0; i < zeroLen; i++) {
				sb.append("0");
			}
			sb.append(strKey);
			sb.append(suffix);
			return sb.toString();
		}

		public synchronized long createKeyAsLong() {
			if (keyCurrent > keyMax) {
				fillKeyBank();
			}
			long l = keyCurrent;
			keyCurrent++;
			return l;
		}

		public synchronized boolean initKeyBank() {
		
			int u1 = baseKeysRepository.incrementKeyValue(name);
			
//			CacheManager cache = CacheManager.getInstance(); 
//			Map<String,Object> map = cache.getMapCache(); 
			
			CacheContainer cache = CacheContainer.getInstance(); 
			
			KeyBankPO basekey = (KeyBankPO)cache.get("flowNoCache", name);
			
			Long currNumber = Long.parseLong((String)cache.get("flowNoCache", "0"+name));
			
			currNumber += basekey.getKeyCache();
			cache.put("flowNoCache","0"+name, currNumber.toString());
			
			
			boolean result = false;
			if (u1 > 0) {
				
				basKeysVO = (KeyBankPO) baseKeysRepository.findByKeyName(name);

				keyMax = Long.parseLong(basKeysVO.getKeyValue());
				keyCurrent = keyMax - basKeysVO.getKeyCache().longValue() + 1;
				result = true;

			}
			return result;
		}

		protected synchronized boolean fillKeyBank() {

			boolean result = true;
			
			CacheContainer cache = CacheContainer.getInstance(); 
			
			KeyBankPO basekey = (KeyBankPO)cache.get("flowNoCache", name);
			
			Long currNumber = Long.parseLong((String)cache.get("flowNoCache", "0"+name));
			
			currNumber += basekey.getKeyCache();
			cache.put("flowNoCache","0"+name, currNumber.toString() );
			
			keyMax = currNumber;
			keyCurrent = keyMax - basekey.getKeyCache() + 1; 
			
			
			return result;
		}
	}
	
	private static String parseValue(String str){
		
		int startIndex = str.indexOf("${");
		
		int endIndex = str.lastIndexOf("}");
		
		if(startIndex != -1 && startIndex<endIndex ){
			
			String value = str.substring(startIndex+2,endIndex); 
			
			String dateString = DateUtil.getDateTime();
			if(value.equals("date12")){
				dateString = dateString.substring(2,14);
			}else if(value.equals("date6")){
				dateString = dateString.substring(2,8);
			}else if(value.equals("date4")){
				dateString = dateString.substring(4,8);
			}else if(value.equals("date8")){
				dateString = dateString.substring(2,10);
			}
			
				
			str = str.substring(0,startIndex) + dateString + str.substring(endIndex+1,str.length()); 
			
			
		}
		
		return str; 
	}

	@Override
	public void updateKeyValue() {
		List<KeyBankPO> keyList = baseKeysRepository.findAllKeyBank();
		String keyname = null;
		CacheContainer cache = CacheContainer.getInstance();
		for (KeyBankPO basekey : keyList) {
			keyname = basekey.getKeyName();
			String value = (String) cache.get("flowNoCache", "0" + keyname);
			if (null != value) {
				String value1 = (String) cache.get("flowNoCache", "1" + keyname);
				if (null != value1) {
					if (!value.equals(value1)) {
						baseKeysRepository.updateKeyBankValue(value, keyname);
						cache.put("flowNoCache", "1" + keyname, value);
					}

				}

			}

		}
		
	}

}
